package com.youlai.system.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.converter.DeviceConfigConverter;
import com.youlai.system.global.GlobalData;
import com.youlai.system.helper.ApplicationContextHelper;
import com.youlai.system.mapper.DeviceConfigMapper;
import com.youlai.system.model.entity.DeviceConfig;
import com.youlai.system.model.entity.TrendConfig;
import com.youlai.system.model.query.DeviceConfigQuery;
import com.youlai.system.plugin.opcua.OpcUaHelper;
import com.youlai.system.service.DeviceConfigService;
import com.youlai.system.service.TrendConfigService;
import jakarta.annotation.Resource;
import org.eclipse.milo.opcua.sdk.client.subscriptions.ManagedDataItem;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Service
public class DeviceConfigServiceImpl extends ServiceImpl<DeviceConfigMapper, DeviceConfig> implements DeviceConfigService {

    private final DeviceConfigConverter DeviceConfigConverter;

    private final TrendConfigService trendConfigService;
    @Resource
    private ThreadPoolTaskExecutor taskExecutor; // 假设这是你定义的线程池执行器

    //监听器
    static ManagedDataItem.DataValueListener Trendlistener;
    static ManagedDataItem.DataValueListener DMlistener;

    public DeviceConfigServiceImpl(DeviceConfigConverter DeviceConfigConverter, TrendConfigService trendConfigService) {
        this.DeviceConfigConverter = DeviceConfigConverter;
        this.trendConfigService = trendConfigService;
    }

    @Override
    public boolean deleteDeviceConfig(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的用户数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(","))
                .map(Long::parseLong)
                .collect(Collectors.toList());
        return this.removeByIds(ids);
    }

    public Page<DeviceConfig> getDeviceConfigPage(DeviceConfigQuery DeviceConfigQuery){

        int pageNum = DeviceConfigQuery.getPageNum();
        int pageSize = DeviceConfigQuery.getPageSize();
        String keywords = DeviceConfigQuery.getKeywords();
        Boolean enable = DeviceConfigQuery.getEnable();

        Page<DeviceConfig> DeviceConfigPage = this.page(
                new Page<>(pageNum,pageSize),
                new LambdaQueryWrapper<DeviceConfig>()
                        .like(StrUtil.isNotBlank(keywords),DeviceConfig::getName,keywords)
                        .eq(DeviceConfig::getEnable,enable)
        );

        Page<DeviceConfig> pageResult =  DeviceConfigConverter.entity2Page(DeviceConfigPage);
        return pageResult;
    }

    @Override
    public boolean saveDeviceConfigList(List<DeviceConfig> deviceConfigList) {
        return false;
    }
    // 连接到PLC
    @Override
    public boolean connectPlc(Long id) throws Exception {
        DeviceConfig deviceInfo = getById(id);
        if (deviceInfo != null && !GlobalData.opcUaHelper.isConnected()) {
            GlobalData.opcUaHelper.Connect(deviceInfo.getIp(), deviceInfo.getPort());
            deviceInfo.setConnected(GlobalData.opcUaHelper.isConnected());
            updateById(deviceInfo);
            return GlobalData.opcUaHelper.isConnected();
        }
        return false;
    }

    @Override
    public boolean connectAllPLC() {
        List<DeviceConfig> deviceConfigList = new ArrayList<>();
        deviceConfigList = this.list();

       CountDownLatch latch = new CountDownLatch(deviceConfigList.size());

        // 提交任务到线程池
        for (DeviceConfig deviceConfig : deviceConfigList) {
            if(deviceConfig.getEnable()){

                //获取到当前PLC的节点
                List<String> nodeItems = new ArrayList<>();
                //search device for para...
                LambdaQueryWrapper<TrendConfig> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TrendConfig::getDevice,deviceConfig.getName());
                queryWrapper.eq(TrendConfig::getEnable,true);

                List<TrendConfig> parameterConfigList = trendConfigService.list(queryWrapper);

                // 如果只需要Address字段，那么遍历结果并将Address添加到nodeItems
                for (TrendConfig config : parameterConfigList) {
                    // 假设ParameterConfig实体中有getAddress()方法
                    String address = config.getAddress();
                    if (address != null) {  // 确保地址不是null
                        nodeItems.add(address);
                    }
                }
                List<String> str = nodeItems;

                taskExecutor.execute(createConnectionTask(deviceConfig,  latch, str));
            }
        }

        // 打印最终的连接状态
        for (DeviceConfig deviceConfig : deviceConfigList) {
            System.out.println("IP: " + deviceConfig.getIp() + " - Connected: " + deviceConfig.getConnected());
        }

        return true;
    }


    // 断开PLC连接
    @Override
    public boolean disconnectPlc(Long id) {
        DeviceConfig deviceInfo = getById(id);
        if (deviceInfo != null && GlobalData.opcUaHelper.isConnected()) {
            GlobalData.opcUaHelper.DisConnect();
            taskExecutor.initialize(); // 初始化线程池
            deviceInfo.setConnected(GlobalData.opcUaHelper.isConnected());
            deviceInfo.setSubscribed(GlobalData.opcUaHelper.isSubscribed());
            updateById(deviceInfo);
            return !GlobalData.opcUaHelper.isConnected();
        }
        return false;
    }

    // 开始订阅PLC
    @Override
    public boolean subscribePlc(Long id) throws Exception {
        DeviceConfig deviceInfo = getById(id);
        try {
            if (deviceInfo != null && GlobalData.opcUaHelper.isConnected() && !GlobalData.opcUaHelper.isSubscribed() || true) {
                List<String> opcItems = GlobalData.opcUaHelper.AllTrendNodes();
//              提交任务到线程池 大小16 -> 两次订阅流程4 如果第二次进不去 就扩大一下线程池 需要在断开连接或者取消订阅时初始化线程池
                taskExecutor.execute(() -> {
                    try {
                        GlobalData.opcUaHelper.StartSubscription(deviceInfo,opcItems, Trendlistener);
                    } catch (Exception e) {
                        // 处理异常
                        e.printStackTrace();
                    }
                });
                deviceInfo.setSubscribed(true);
                updateById(deviceInfo);
                return true;
            }
        } catch (Exception e) {
            throw new RuntimeException("订阅节点失败，请检查节点有效性", e);
        }

        return false;
    }

    // 取消订阅PLC
    @Override
    public boolean cancelSubscription(Long id) throws Exception {
        DeviceConfig deviceInfo = getById(id);
        if (deviceInfo != null && GlobalData.opcUaHelper.isSubscribed()) {
            taskExecutor.initialize(); // 初始化线程池
            GlobalData.opcUaHelper.SubscriptionCancel();
            deviceInfo.setSubscribed(false);
            updateById(deviceInfo);
            return ! GlobalData.opcUaHelper.isSubscribed();
        }
        return false;
    }

    // 批量保存设备配置
    @Override
    public boolean saveTrendConfigList(List<DeviceConfig> deviceConfigList) {
        boolean isOK = true;
        try {
            for (DeviceConfig item : deviceConfigList) {
                if (!save(item)) {
                    isOK = false;
                    break; // 如果有一个保存失败，则停止尝试保存剩余的配置
                }
            }
        } catch (Exception e) {
            isOK = false;
            throw new RuntimeException("批量导入错误:", e);
        }
        return isOK;
    }


    // 任务创建方法
    private static Runnable createConnectionTask(DeviceConfig deviceConfig, CountDownLatch latch, List<String> nodeIds) {
        return () -> {
            if (!deviceConfig.getConnected()) {
                String ip = deviceConfig.getIp();
                try {

                    OpcUaHelper opcUaHelper = new OpcUaHelper();
                    opcUaHelper.Connect(ip,4840);
                    deviceConfig.setConnected(true); // 设置连接状态为成功

                    DeviceConfigService deviceConfigService = ApplicationContextHelper.getBean(DeviceConfigService.class);
                    if (deviceConfigService != null) {
                        deviceConfigService.updateById(deviceConfig);
                    }

                    System.out.println(ip + " Connect Finish...." + (deviceConfig.getConnected() ? " Success" : " Failed"));
                    latch.countDown(); // 任务完成，计数器减一

                    //开始订阅
                    opcUaHelper.StartSubscription(deviceConfig, nodeIds, new ManagedDataItem.DataValueListener() {
                        @Override
                        public void onDataValueReceived(ManagedDataItem managedDataItem, DataValue dataValue) {
                            System.out.println("dataValue = " + dataValue);
                        }
                    });

                } catch (Exception e) {
                    System.err.println("Failed to connect to " + ip + ": " + e.getMessage());
                    deviceConfig.setConnected(false); // 设置连接状态为失败
                }
            } else {
                System.out.println(deviceConfig.getIp() + " is not configured to connect.");
                latch.countDown(); // 任务完成，计数器减一
            }
        };
    }

}
